home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr44 / xlib50.zip / DONTREAD.ME < prev    next >
Text File  |  1995-02-11  |  52KB  |  886 lines

  1. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. ;+                                                                             +
  3. ;+                        DONTREAD.ME Version 2.0                              +
  4. ;+                 A Tutorial for XLIB and Protected Mode                      +
  5. ;+                                                                             +
  6. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  7. ;
  8. ;   If you don't read much, then this file was made just for you.  It's 
  9. ;a lot shorter than XLIB.DOC.  It also explains several protected-mode 
  10. ;concepts, including some that are needed to understand XLIB.DOC.  We work
  11. ;through an assembly language program which demonstrates the usage of XLIB.
  12. ;As we go, we are going to do a lot of talking about protected mode in 
  13. ;general as well as protected mode under XLIB in particular.
  14. ;   First, let's talk about what XLIB is generally designed to do:  XLIB 
  15. ;will allow you to write protected-mode procedures using your familiar 
  16. ;language development tools (compilers, linkers, etc), and will allow you to
  17. ;execute code containing such procedures using DOS.  XLIB is also designed
  18. ;to make all this as simple for you as it possibly can.  That turns out to
  19. ;very simple indeed.
  20. ;   XLIB has one major shortcoming:  It relies on DOS to load executables
  21. ;and files.  This means that our code must reside in the first meg because
  22. ;that's the only thing DOS knows how to work with.  It also means that when
  23. ;we transfer disk files to or from extended memory, we must perform a 
  24. ;transfer through a buffer in the first meg.  In almost every other regard, 
  25. ;we will have unlimited power.  Most importantly, we will be able to access 
  26. ;data in extended memory with extreme ease and speed.
  27. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  28.  
  29. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  30. ;   Now, let's start with a little program.  We must begin with a model 
  31. ;declaration.  XLIB is a large-model library which uses PASCAL conventions.  
  32. ;We will use the same model here; however, this is not a requirement of XLIB.
  33. ;We will use the FARSTACK option because this ensures that our real-mode
  34. ;stack will be at the end of the program.  This is where it should be under
  35. ;most circumstances anyway, but TASM doesn't always put it there (see the
  36. ;section on bugs in README.DOC).  FARSTACK allows us to conclude that the
  37. ;initial SS:SP points to the end of the program.  This will become useful
  38. ;information a few lines down.  We also want to tell the assembler to let us 
  39. ;use 32-bit instructions.  We do this with the .386 directive.
  40. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  41.  
  42.                .MODEL         LARGE,PASCAL,FARSTACK
  43.                .386
  44.  
  45. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  46. ;   The next two line are the key ingredients.  We want to provide XLIB 
  47. ;symbols to this program with XLIB.INC.  We also want to link with XLIBE.LIB.  
  48. ;XLIBE.LIB has exception trapping capabilities whereas XLIB.LIB does not.
  49. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  50.  
  51.                INCLUDE        XLIB.INC
  52.                INCLUDELIB     XLIBE.LIB
  53.  
  54. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  55. ;TASM Only:
  56. ;
  57. ;   If you are a TASM programmer, then don't use the last two lines.  Use the
  58. ;following lines instead.  These lines include some useful macros that should 
  59. ;have been in TASM to begin with.
  60. ;
  61. ;              MASM51                        ;Emulate MASM51
  62. ;              QUIRKS                        ;MASM51 quirks are sometimes nice
  63. ;
  64. ;PUSHW         MACRO IMMEDIATE16:REST        ;PUSH 16-bit constant
  65. ;              IF (@WordSize EQ 4)
  66. ;              DB             66H
  67. ;              ENDIF
  68. ;              DB             68H
  69. ;              DW             IMMEDIATE16
  70. ;              ENDM
  71. ;
  72. ;PUSHD         MACRO IMMEDIATE32:REST        ;PUSH 32-bit constant
  73. ;              IF (@WordSize EQ 2)
  74. ;              DB             66H
  75. ;              ENDIF
  76. ;              DB             68H
  77. ;              DD             IMMEDIATE32
  78. ;              ENDM
  79. ;
  80. ;              INCLUDE        XLIBB.INC
  81. ;              INCLUDELIB     XLIBEB.LIB
  82. ;
  83. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  84.  
  85. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  86. ;  Now we will finish our simplified segment directives.
  87. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  88.  
  89.                .STACK         1024
  90.                .DATA
  91.                .CODE
  92.                .STARTUP
  93.  
  94. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  95. ;   Now we have to deal with an annoying complication.  XLIBE.LIB might need 
  96. ;to allocate some conventional memory for its own use.  The problem is that 
  97. ;our program has likely claimed all available memory, even though it isn't 
  98. ;going to use it.  If you are a MASM programmer, then the solution is simple:  
  99. ;Link with the CPARM:1 parameter.  If you are a TASM programmer, then you 
  100. ;must resize the memory block in which this program is contained.  The 
  101. ;following code will do the trick.  This code is also contained in the file
  102. ;RESIZE.INC.
  103. ;
  104. ;              MOV            AX,SP          ;SS:SP = end of program
  105. ;              SHR            AX,4
  106. ;              MOV            BX,SS
  107. ;              ADD            BX,AX
  108. ;              INC            BX             ;BX = first para. beyond program
  109. ;              MOV            AX,ES          ;ES:0000 = first para. of program
  110. ;              SUB            BX,AX          ;BX = program size in para.
  111. ;              MOV            AH,4AH         ;Function to resize memory block
  112. ;              INT            21H            ;Carry will be set if failure
  113. ;              JNC            STILLGOING
  114. ;              MOV            AX,4C01H       ;Failed to resize so terminate
  115. ;              INT            21H
  116. ;STILLGOING:
  117. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  118.  
  119. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  120. ;   One more step and we will be ready to hit protected mode!!!  We must
  121. ;initialize the library by calling INITXLIB.  This procedure will return an
  122. ;error code in EAX.  A code of zero always means success under XLIBE.
  123. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  124.  
  125.                CALL           INITXLIB
  126.                OR             EAX,EAX
  127.                JZ             GOTPOWER
  128.                MOV            AX,4C01H       ;DOS termination function
  129.                INT            21H            ;You will have to read after all.
  130.                                              ;If you simply can't stand user
  131.                                              ;manuals, then try throwing out
  132.                                              ;some device drivers and TSRs.
  133. GOTPOWER:
  134.  
  135. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  136. ;   We don't want to mess around in real mode anymore.  As you will shortly 
  137. ;see, we can do about anything in protected mode that we could do in real 
  138. ;mode, plus a whole lot more.  Moreover, XLIBE makes protected mode easier 
  139. ;than real mode.  We will spend the rest of our time working from a 32-bit 
  140. ;protected-mode subroutine called PMMAIN.  We will get there with an XLIBE 
  141. ;procedure called CALLPM.  Just push the offset of PMMAIN on the stack and 
  142. ;call CALLPM.
  143. ;   There is one big assumption involved here:  It is assumed that PMMAIN and 
  144. ;all other 32-bit routines are contained in a segment called TSEG.  Don't 
  145. ;worry, TSEG can be larger than 64K if you live by the rules.  Read the 
  146. ;manual if you want to know what they are.
  147. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  148.  
  149.                PUSHD          OFFSET PMMAIN  ;Must use a 32-bit offset
  150.                CALL           CALLPM
  151.  
  152. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  153. ;   XLIBE is going to use the return address from the above call to find its
  154. ;way back to real mode.  You can get back to real mode by using the RET
  155. ;instruction provided that you have maintained the stack pointer.  If this is
  156. ;not the case, then you can still get back with no problem.  More about this
  157. ;later.  When we get back, we are just going to terminate.
  158. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  159.  
  160.                MOV            AX,4C00H
  161.                INT            21H
  162.  
  163. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  164. ;   Now we will declare our 32-bit segment.  We will later talk about
  165. ;protected mode segments in general and about 32-bit segments in particular.
  166. ;Just hang loose for now.  It is all simple.
  167. ;   When we arrive at this segment from CALLPM, our segment registers will
  168. ;have been loaded by XLIBE.  They will be set as follows:  CS will have
  169. ;TSEG base and a 4Gb limit (Gb = gigabyte).  SS will also have TSEG base and
  170. ;a 4Gb limit; however, code segments and data segments are distinguished in
  171. ;protected mode.  We will have 4096 free bytes on the stack.  DS will have a
  172. ;zero base and 4Gb limit.  This is what is called a "flat" segment.  ES will
  173. ;have TSEG base and a 4Gb limit (same as SS).  FS will have DSEG base and a 
  174. ;64K limit.  DSEG is the data segment used by XLIB.  Finally, GS will have 
  175. ;DGROUP base and a 64K limit.  DGROUP is the segment group created by the 
  176. ;.DATA directive.  If you are a high-level language programmer, then DGROUP
  177. ;is also where your compiler probably puts all of the near data.
  178. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  179.  
  180. TSEG           SEGMENT PARA PUBLIC USE32 'CODE'
  181.                ASSUME CS:TSEG, SS:TSEG, ES:TSEG, FS:DSEG, GS:DGROUP
  182.  
  183. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  184. ;   Now let's look at the PMMAIN procedure below.  You will see that it is a 
  185. ;near procedure.  This must be the case for all procedures called by CALLPM.  
  186. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  187.  
  188. PMMAIN         PROC NEAR
  189.  
  190. ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  191. ;   We are in 32-bit protected mode
  192. ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  193.  
  194. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  195. ;   By the way, you will get all registers except segment registers and ESP 
  196. ;at the values you had in them in real mode, including status flags (carry 
  197. ;flag, zero flag, etc) and the interrupt flag.  The stack got switched on 
  198. ;you, so don't try passing stack arguments through CALLPM.  If you have 
  199. ;arguments, then send them across in registers (e.g. load a register with a
  200. ;pointer to a structure containing all arguments).
  201. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  202.  
  203. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  204. ;   Of course, no language tool can be legitimate unless it can say "hello" 
  205. ;to the world, so let's take care of this important business now.  We will 
  206. ;use DOS function 02H for this purpose.
  207. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  208.  
  209.                MOV            EBX,OFFSET HELLOWWORLD
  210.                MOV            AH,02H
  211. GETCHAR:       MOV            DL,CS:[EBX]    ;Read with CS but don't write!!!
  212.                OR             DL,DL
  213.                JZ             GOODBYEWORLD
  214.                INT            21H            ;DOS interrupt
  215.                INC            EBX
  216.                JMP            GETCHAR
  217.  
  218. HELLOWWORLD    DB "Hello world!",0
  219.  
  220. GOODBYEWORLD:
  221.  
  222. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  223. ;   Did you forget that DOS is a real-mode system???  If not then you could
  224. ;be wondering how we got away with what we just did (i.e. INT 21H).  The
  225. ;answer is simple.  At this point, XLIBE is trapping all interrupts occurring 
  226. ;in protected mode.  It is then switching to real mode and relaying the call 
  227. ;to the corresponding real-mode interrupt handler.  Finally, it is switching 
  228. ;back to protected mode and returning control to us.  This is commonly called
  229. ;"reflection."  We call it "deflection" in XLIB.DOC.  Any interrupt will 
  230. ;continue to be deflected until you install your own protected-mode interrupt 
  231. ;handler for the interrupt.
  232. ;   Therefore, we can still use our favorite software interrupts with one 
  233. ;provision:  These interrupts cannot return values in the segment registers.  
  234. ;Such values would be overwritten with segment selectors on the way back to 
  235. ;protected mode.  More about segment selectors later.
  236. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  237.  
  238. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  239. ;   Now, let's get down to real business.  Your principal interest in 
  240. ;protected mode was likely access to extended memory.  Well, it is now there 
  241. ;for the taking.  However, we must play by the rules.  If you just start
  242. ;punching around in extended memory, then you could get a nasty thing called 
  243. ;a "page fault."  We will talk more about this later.  Also, somebody else 
  244. ;might be up there - like your disk cache or your ram drive.  Mess with those
  245. ;and you are going to feel real bad.
  246. ;   The safe approach is to allocate the extended memory with the PMGETMEM 
  247. ;function.  Just load EAX with the number of bytes you want and call 
  248. ;PMGETMEM.  Let's get 64K.
  249. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  250.  
  251.                MOV            EAX,10000H
  252.                CALL           PMGETMEM
  253.  
  254. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  255. ;   PMGETMEM will return with an error code in EAX.  If EAX = 0, then the
  256. ;address of the allocated block will be in EDX.  The actual size of the block
  257. ;will be in ECX, and a handle for the block will be in EBX.  The allocated
  258. ;size will always be at least as large as your request.  You will need the
  259. ;handle in EBX in the event that you later want to release the block;
  260. ;however, there is little need to worry about this.  XLIBE will release it 
  261. ;for you automatically when you terminate.
  262. ;   Now, let's see if we got an error from PMGETMEM.  If so, then we will
  263. ;return to real mode using the near RET instruction; otherwise, we will zero
  264. ;the entire allocated block just for fun.
  265. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  266.  
  267.                OR             EAX,EAX
  268.                JZ             ZEROMEMORY
  269.                RET                           ;Go back to real mode
  270.  
  271. ZEROMEMORY:    SUB            ECX,4          ;ECX is always a multiple of 4
  272.                MOV            [EDX+ECX],EAX  ;EAX = 0 from PMGETMEM
  273.                JNZ            ZEROMEMORY
  274.  
  275. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  276. ;   The RET instruction is an easy way to get back home, but suppose you had
  277. ;pushed some stuff on the stack since the call to CALLPM.  Then RET would be
  278. ;potentially disastrous.  In this case you get back to real mode by jumping 
  279. ;to a procedure call RETPM.  The following instruction would do the trick:
  280. ;
  281. ;              JMP            RETPM
  282. ;
  283. ;You can use this instruction just about anywhere.
  284. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  285.  
  286. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  287. ;   Now, suppose you have a bug somewhere along here and you therefore wish 
  288. ;to look at your register values.  This is easy under XLIBE.  Just use the 
  289. ;INT 3 instruction.
  290. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  291.  
  292.                INT            3
  293.  
  294. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  295. ;   INT 3 generates a breakpoint exception.  XLIBE will trap this exception
  296. ;and print a report to the screen.  This report will contain register state
  297. ;and other useful information.  From the report screen you will be given the
  298. ;option to resume execution.  XLIBE will attempt to trap and report all CPU
  299. ;exceptions in this manner.  Expect to get plenty of them in protected mode.  
  300. ;Don't worry, they are not going to crash your machine all the time like they 
  301. ;did in the old days.  XLIBE is pretty good at cleaning up your mess.
  302. ;   See the special note below if you want to know how XLIBE is going to 
  303. ;handle your FPU exceptions.
  304. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  305.  
  306. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  307. ;   OK.  You already know enough about XLIBE to write some powerful code.
  308. ;You might not be interested in the remaining examples, so let's talk for a
  309. ;while about what you need to know concerning protected mode in general, and 
  310. ;then you can get to programming if you wish.
  311. ;   The principle difference between protected mode and real mode from the
  312. ;programmer's perspective is the interpretation of the segment registers.  In
  313. ;real mode the value in the segment register is multiplied by 16 and then
  314. ;added to an offset to get an address.  For example, consider:  MOV AX,[BX].
  315. ;This instruction implicitly uses the DS register for the memory access.
  316. ;Suppose DS = 02FFH and BX = 4004H, then AX would be loaded from 6FF4H (or 
  317. ;10H * 02FFH + 4004H).  It's simple, but it is also very limiting.
  318. ;   By the way, 4004H would be called the "effective" address while 6FF4H 
  319. ;would be called the "linear" address.  The "base" address of the segment is 
  320. ;simply the linear address at offset zero.  In this case, the base address is 
  321. ;2FF0H.
  322. ;   Now we will find out what stinks about real mode:  The largest value
  323. ;you could have in DS is FFFFH (64K - 1).  The largest offset you could have 
  324. ;is also FFFFH.  This means that the largest linear address you could get in 
  325. ;real mode is 10FFEFH.  That's 1 meg plus about 64K.  Isn't much these days.
  326. ;You wouldn't be reading this if it were.
  327. ;   In fact, you can't even get 10FFEF if you have only 20 address lines (as 
  328. ;in the 8086).  In this case you would be limited to FFFFFH, the largest 
  329. ;number that can be expressed with 20 bits.  That's where the one meg 
  330. ;limitation came in.
  331. ;   The addresses beyond FFFFFH and up to 10FFEFH are commonly called the
  332. ;"HMA" (high memory area).  You get them from real mode when you have got
  333. ;more than 20 address lines (as in the 286 or higher).  The "A20" you may 
  334. ;have heard about is the 21st address line (the first one is numbered zero).
  335. ;   In protected mode, the segment registers contain "selectors."  Selectors
  336. ;index system tables called "descriptor tables."  Under XLIBE, your selectors
  337. ;will be indexing the "local descriptor table" or LDT.  The entries in these 
  338. ;tables contain "descriptors."  These are each eight bytes long.  XLIBE sets 
  339. ;them all up for you.
  340. ;   The descriptors specify many things concerning a segment; however, two 
  341. ;are of special importance.  First, these descriptors specify the base 
  342. ;address of the segment.  Second, they specify the limit of the segment.  The 
  343. ;limit is the largest offset that can be used in conjunction with the 
  344. ;segment.  The nice thing about protected mode is that both the base and the 
  345. ;limit can be as large as FFFFFFFFH (that's 4Gb - 1).
  346. ;   One of the reasons that we use the term "protected mode" is the 
  347. ;enforcement of the limits on the segments.  Suppose you had DS loaded with
  348. ;a descriptor having FFFH limit, and suppose you tried to execute something
  349. ;like MOV AX,[1000H], then you will have violated protection rules and the
  350. ;processor will shut you down with an exception #13.  Hence, memory outside
  351. ;of the segment is somewhat protected.  Actually, there are other protection
  352. ;mechanisms far more important than this.  More later.
  353. ;   Observe that we could get mighty close to emulating real mode from within
  354. ;protected mode.  We could load segment registers with base addresses less
  355. ;than FFFFFH and fix their limits at FFFFH.  Then all we would need to do
  356. ;is make the processor interpret loads to the segment registers as changes
  357. ;to their base addresses (actually, a little more would be necessary).  In 
  358. ;fact this can be done.  It's called "virtual 8086 mode."  You are using it 
  359. ;right now if you have something like EMM386, 386MAX, or QEMM386 loaded.  You
  360. ;may be surprised to know that you have been using protected mode all along!
  361. ;   So, the moral to the above story is:  A segment register must never be 
  362. ;loaded with anything but a selector to a valid descriptor.  In real mode you 
  363. ;could always execute MOV DS,AX.  This isn't going to work in protected mode 
  364. ;unless AX contains a selector.  If it doesn't, then an exception #13 is 
  365. ;headed your way.
  366. ;   OK.  The next major difference between the two modes has already been
  367. ;mentioned:  In real mode, your offsets cannot be greater than FFFFH.  In
  368. ;protected mode they can be as great as your segment limit, and that usually
  369. ;means 4 gig.  By the way, there is nothing inherent to real mode that would
  370. ;logically prevent segment limits greater than FFFFH.  The processor imposes
  371. ;this limit to enforce emulation of the 8086.  If we could persuade the 
  372. ;processor to lift this restriction, then we would find ourselves with a 
  373. ;really powerful real mode.  In fact this can be done on the data segments,
  374. ;and is done in some software (e.g. HIMEM.SYS).
  375. ;   Perhaps you have heard of something called the "flat model" or 
  376. ;"unsegmented model."  This is a protected-mode model in which we set all 
  377. ;segment base addresses to zero and set all segment limits to FFFFFFFFH.
  378. ;This makes life real easy, and it's probably where we are headed in the 
  379. ;future.  XLIBE tries to get you as close to this model as it can so that you 
  380. ;won't have to be changing your code when your future finally gets here.
  381. ;   Now let's talk about 32-bit processing as opposed to 16-bit processing.  
  382. ;There are a few things you need to know.  Notice that we have "USE32" on the 
  383. ;TSEG segment declaration above.  This is why we call TSEG a 32-bit segment.
  384. ;Segments you have used in times past had the USE16 attribute (the default).  
  385. ;DSEG and DGROUP are also USE16 segments.  You have probably guessed that 
  386. ;USE16 gives you a 16-bit segment.  The difference derives from a peculiarity 
  387. ;of the processor.  For most instructions, the processor has both a 16-bit 
  388. ;version and a 32-bit version.  The peculiarity is that the op codes are 
  389. ;generally the same.  Consider PUSH AX as opposed to PUSH EAX.  Would you 
  390. ;believe that they are encoded exactly the same?  The op code is 50H either 
  391. ;way.
  392. ;   So how do we tell the difference?  Well, it's done with a single bit in 
  393. ;the code segment descriptor.  If this bit is set, then the instruction will 
  394. ;be interpreted as having a 32-bit operand.  It will be interpreted as a 
  395. ;16-bit instruction otherwise.  This bit is called the "D bit" (default 
  396. ;operand/address size).  
  397. ;   So, what if you really wanted a PUSH AX even when this curious bit is 
  398. ;set?  You do this by encoding an "operand prefix" in front of the 
  399. ;instruction.  The prefix is 66H.  So if we want PUSH AX from within 32-bit 
  400. ;mode, then we encode the instruction as 66H followed by 50H.  Conversely, if 
  401. ;we wanted PUSH EAX in 16-bit mode, then we must also encode it as 66H 
  402. ;followed by 50H.  Thus, the 66H temporarily places the processor in the 
  403. ;opposite mode dictated by the D bit.
  404. ;   The USE32 directive informs the assembler that we intend to execute in 
  405. ;the declared segment with the D bit set.  This information lets the 
  406. ;assembler know that it must stick operand prefixes in front of 16-bit 
  407. ;instructions.  Accordingly, USE16 tells the assembler that we are going
  408. ;to execute in the declared segment with the D bit clear.  Now the assembler
  409. ;must stick the operand prefix in front of 32-bit instructions.  
  410. ;   A similar situation exists for base registers and index registers.  For
  411. ;example, MOV AL,[EBX] and MOV AL,[BX] are identically encoded apart from a
  412. ;prefix.  The prefix in this case is 67H.  A 67H enables a MOV AL,[BX] in
  413. ;a 32-bit segment, or MOV AL,[EBX] in a 16-bit segment.  The USE32 and USE16
  414. ;directives tell the assembler where to insert 67H.
  415. ;   What if we had MOV AX,[BX] in a 32-bit segment?  Then we must encode both
  416. ;prefixes (67H must be first).
  417. ;   You have probably gathered that 16-bit instructions are bad in a 32-bit
  418. ;segment.  They obviously require more memory.  What isn't obvious is that
  419. ;they burn up CPU time (typically 1 clock each on the 486).  So avoid 16-bit 
  420. ;registers while in TSEG.  8 bit registers are OK in either kind of segment.
  421. ;   Observe that the D bit has little to do with protected-mode.  We could
  422. ;run a protected-mode program in a 16-bit segment, but then we have to pay
  423. ;a price for using 32-bit registers.  That just isn't smart.  The only 
  424. ;association between the D bit and protected mode is that you must be in
  425. ;protected mode if the D bit is set.  There is no such thing as 32-bit
  426. ;real mode, even though it is conceptually possible.
  427. ;   OK.  There is one other thing that you should perhaps understand.  Its
  428. ;called "page mode," but the concept is a little complicated, so we have 
  429. ;placed it at the bottom of this file.  You can read it if you like, but
  430. ;will be OK without it.
  431. ;   If you are ready to leave, then we can terminate our program with the
  432. ;following lines:
  433. ;
  434. ;
  435. ;              RET                           ;Go back to real mode
  436. ;PMMAIN        ENDP
  437. ;
  438. ;TSEG          ENDS
  439. ;              END
  440. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  441.  
  442. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  443. ;   Back to our discussion about XLIBE.  From now on we are going to deal 
  444. ;with you bad guys.  
  445. ;   Let's suppose you have an IO device which maps to extended memory 
  446. ;addresses.  You need to read or write to these addresses.  The memory is 
  447. ;supplied by the device and is not recognized as ordinary RAM by the 
  448. ;operating system.  The operating system may not even know that it is there.  
  449. ;Let's suppose that the device map begins at the 16th meg boundary (1000000H) 
  450. ;and is 64K long.  
  451. ;   It would not be wise just to start poking and peeking around 1000000H.
  452. ;There is a problem in that your device maps to "physical" addresses whereas 
  453. ;your instruction code is using "logical" addresses.  They may not be the 
  454. ;same.  See the discussion about page mode below if you want to understand 
  455. ;the difference.
  456. ;   You need to create a logical address space for accessing the device.  
  457. ;This is very simple.  Just call PMMAPIO with EDX = the physical address of 
  458. ;the device and EAX = the size of the window.
  459. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  460.  
  461.                MOV            EDX,1000000H
  462.                MOV            EAX,10000H
  463.                CALL           PMMAPIO
  464.  
  465. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  466. ;   PMMAPIO returns an error code in EAX.  If EAX = 0, then EDX will equal 
  467. ;the starting address at which the device should be accessed.  We will check 
  468. ;out this error code before we continue.
  469. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  470.  
  471.                OR             EAX,EAX
  472.                JZ             MOREHARDCORE
  473.                RET                           ;Back to real mode
  474. MOREHARDCORE:
  475.  
  476. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  477. ;   OK.  Now let's suppose you have a great big database on disk that you 
  478. ;have never been able to completely read into memory because of DOS 
  479. ;limitations.  We are fixing to load the whole thing.  First, we must 
  480. ;allocate memory to contain the file.  Let's do that now.  We are going to
  481. ;assume that the file will never be larger than one meg, but you could 
  482. ;increase the assumed limit if you wanted.
  483. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  484.  
  485.                MOV            EAX,100000H    ;Get 1 Meg of memory for file
  486.                CALL           PMGETMEM
  487.                OR             EAX,EAX        ;See if an error occurred
  488.                JZ             WAYDOWN
  489.                RET                           ;Back to real mode
  490.  
  491. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  492. ;   Next, we need to set up a file control block (not a DOS FCB) to describe 
  493. ;the file to XLIBE.  XLIBE will expect the control block to be in the form of 
  494. ;the structure below.
  495. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  496.  
  497. XFILE          STRUCT
  498.   CONDCODE     DWORD          0          ;Condition code from file operation
  499.   FNAME        BYTE  68 DUP(0)           ;ASCII file path (zero terminated)
  500.   FHANDLE      WORD           0          ;File handle assigned by DOS
  501.   FPTRMODE     WORD           0          ;File pointer reference
  502.   FPTR         DWORD          0          ;Initial file pointer
  503.   BLOCKADR     DWORD          0          ;Memory source/destination address
  504.   BLOCKSIZE    DWORD          0          ;Size of transfer block in bytes
  505.   BUFFERADR    DWORD          0          ;Address of memory buffer in 1st meg
  506.   BUFFERSIZE   WORD           0          ;Buffer size in bytes
  507.   CONTROL      WORD           0          ;Control word
  508. XFILE          ENDS
  509.  
  510. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  511. ;TASM Only:
  512. ;   If you are a TASM programmer, then don't use the structure above.  Use:
  513. ;
  514. ;XFILE         STRUC
  515. ;  CONDCODE    DD             0
  516. ;  FNAME       DB  68 DUP(0)
  517. ;  FHANDLE     DW             0
  518. ;  FPTRMODE    DW             0
  519. ;  FPTR        DD             0
  520. ;  BLOCKADR    DD             0
  521. ;  BLOCKSIZE   DD             0
  522. ;  BUFFERADR   DD             0
  523. ;  BUFFERSIZE  DW             0
  524. ;  CONTROL     DW             0
  525. ;XFILE         ENDS
  526. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  527.  
  528. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  529. ;Let's suppose that the filename is JUNK.DAT and that this file is in the 
  530. ;current directory.  If you want to run this program, then create a small 
  531. ;text file called JUNK.DAT in the current directory.  We are going to get
  532. ;the assembler to put our file name in the structure.  The rest we will punch
  533. ;in ourselves.  Remember that EDX is the linear address of the memory block
  534. ;where we are going to load this file.  ECX is the size of the block.  We
  535. ;obtained these values from PMGETMEM above.  Also, remember that ES is loaded
  536. ;with a selector to TSEG.
  537. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  538.  
  539.                ALIGN          4              ;Unaligned data will slow you down
  540. FCB            XFILE          <0,"JUNK.DAT"> ;File control block
  541.  
  542. WAYDOWN:       MOV            ES:FCB.BLOCKADR,EDX
  543.                MOV            ES:FCB.BLOCKSIZE,ECX
  544.                MOV            ES:FCB.BUFFERSIZE,0H
  545.  
  546. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  547. ;   OK. Lets get the file and talk about it later.  We will need to call
  548. ;PMXLOAD.  PMXLOAD will expect EAX to contain the linear address of the file
  549. ;control block.  Here we go.
  550. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  551.  
  552.                MOV            EAX,TSEG       ;Get segment of control block
  553.                SHL            EAX,4          ;Multiply by 16 and add offset
  554.                ADD            EAX,OFFSET FCB ;EAX = linear address now
  555.                PUSH           EAX            ;We will use this again
  556.                CALL           PMXLOAD
  557.  
  558. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  559. ;   Now, we will explain what we just did.  BLOCKADR is the address of the 
  560. ;memory block where we want the file to be loaded.  BLOCKSIZE is the size of 
  561. ;this block.  PMXLOAD will not load past the end of the block since that 
  562. ;could be very dangerous to you or whoever else might be in memory.  Now, DOS
  563. ;is going to access the disk for us, but DOS can't work with extended memory.
  564. ;So, we set up a buffer in conventional memory for DOS.  PMXLOAD will handle
  565. ;the transfers from the buffer to extended memory.  You could supply your 
  566. ;own buffer address and size in BUFFERADR and BUFFERSIZE; however, if you
  567. ;will just set BUFFERSIZE to zero, then XLIBE will supply its own buffer.
  568. ;   PMXLOAD will return an error code in both EAX and CONDCODE (same error
  569. ;code).  We will check it now.
  570. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  571.  
  572.                OR             EAX,EAX
  573.                JZ             GOTFILE
  574.                JMP            RETPM          ;Back to real mode
  575. GOTFILE:
  576.  
  577. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  578. ;   Notice that if an error occurs, then we transfer control back to real 
  579. ;mode with JMP RETPM rather than RET.  This is because we've got some stuff
  580. ;on the stack now; namely, the linear address of our file control block.  Of
  581. ;course a POP EAX followed by a RET would still work.
  582. ;   OK.  Suppose you play around with memory image of the file, perhaps 
  583. ;making a few modifications.  Now you want to save it.  The file control 
  584. ;block should be defined as before, except BLOCKSIZE and BLOCKADR should
  585. ;specify the address and size of the memory block you are going to save.
  586. ;PMXLOAD modified BLOCKSIZE in the file control block.  It was set to the
  587. ;actual size of the file that it loaded.  This means that unless you have
  588. ;changed the size of the memory image, then you need to make no further 
  589. ;modifications to the file control block to perform the save.  Just call
  590. ;PMXSAVE with the address of the control block in EAX.  Here we go.
  591. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  592.  
  593.                POP            EAX            ;Get FCB address
  594.                CALL           PMXSAVE
  595.                OR             EAX,EAX        ;See if an error occurred
  596.                JZ             FILEISSAVED                                      
  597.                RET
  598. FILEISSAVED:
  599.  
  600. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  601. ;   XLIBE can also perform random reads and writes with files.  See the 
  602. ;manual if you want to know more.
  603. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  604.  
  605. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  606. ;   One more topic.  This concerns interrupt handlers.  These are real devils
  607. ;in any mode.  Unfortunately, XLIBE can't simplify matters as much as it would
  608. ;like.  This is because XLIBE must work in conjunction with other software
  609. ;(VCPI or DPMI) to give you all of this protected-mode stuff.  This other
  610. ;software doesn't handle interrupts the same, and there isn't much that XLIBE
  611. ;can do to smooth out the lumps.  You better read the manual on this one.
  612. ;   Anyway, we are going to install a simple timer-tick interrupt which will
  613. ;print an asterisk to the screen with each timer tick.  We are going to use
  614. ;routines in the file PMIO.INC to do the printing.  You will see that we have
  615. ;INCLUDE PMIO.INC several lines down in the code.
  616. ;   PMIO.INC is a very handy little file and is very simple to use.  Examine
  617. ;the file if you want to know more.  The comments in the file explain how to
  618. ;use the PMIO procedures.
  619. ;   Let's clear the screen before we get started with our interrupt handler.
  620. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  621.  
  622.                CALL           CLS
  623.  
  624. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  625. ;   OK.  We are going to install our own protected-mode interrupt handler for
  626. ;the timer tick.  The timer tick is a hardware interrupt on IRQ 0.  First, we
  627. ;need to get the current protected-mode interrupt vector so we can restore it
  628. ;when we are done.
  629. ;   Now the timer tick is generally at vector eight (INT 8), but we must deal
  630. ;with the possibility that XLIBE has remapped interrupts.  We can't assume that
  631. ;IRQ 0 is still assigned to INT 8.  The current mapping is contained in the
  632. ;XLIBE data area (DSEG) in a variable called IRQ0INTNO.  Let's get it now.
  633. ;Remember that FS contains a selector for DSEG.
  634. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  635.  
  636.                MOV            AL,FS:IRQ0INTNO
  637.  
  638. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  639. ;   OK.  To get the current vector, we need merely to call PMGETPMIV (get
  640. ;protected-mode interrupt vector) with the vector number in AL.  The address
  641. ;of the current interrupt handler will be returned in CX:EDX.  Here we go.
  642. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  643.  
  644.                CALL           PMGETPMIV      ;No error code from this call
  645.                PUSH           ECX            ;Save handler address on stack
  646.                PUSH           EDX
  647.  
  648. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  649. ;   Now we will set our new vector.  We must call PMSETPMIV with AL = the
  650. ;interrupt number and CX:EDX = the new handler address.  CX must be a segment
  651. ;selector.  Our new handler is called TIMERINT.  It is located just a few 
  652. ;lines down.  We will get there in just a moment.  PMSETPMIV will return an
  653. ;error code in EAX.  We will check this, as always.
  654. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  655.  
  656.                PUSH           CS             ;Put handler address in CX:EDX
  657.                POP            ECX                             
  658.                MOV            EDX,OFFSET TIMERINT                              
  659.                CALL           PMSETPMIV
  660.                OR             EAX,EAX        ;Check error code
  661.                JZ             WATCHTICKS
  662.                JMP            RETPM          ;Back to real mode
  663. WATCHTICKS:
  664.  
  665. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  666. ;   Notice that we treated PUSH CS as though it put 4 bytes on the stack.
  667. ;It did.  In 32-bit mode, the processor tries to keep the stack aligned at
  668. ;MOD 4.  So, it padded the PUSH with a two-byte zero.  It will always do
  669. ;this with segment registers (on far calls, on interrupts, on everything), 
  670. ;and you would do well to remember it.
  671. ;   OK.  Now we need a little loop to delay long enough for a few timer
  672. ;ticks to happen.  There are about 18.2 of them in a second.  If you have
  673. ;a 486-33, then the next loop will work fine.  If you have a 386, then you
  674. ;may be watching ticks for a while.
  675. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  676.  
  677.                MOV            ECX,0FFFFFFH
  678. WAITAWHILE:    LOOP           WAITAWHILE     ;Asterisks are being printed
  679.  
  680. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  681. ;   That's enough.  Let's put the old vector back.
  682. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  683.  
  684.                POP            EDX
  685.                POP            ECX
  686.                MOV            AL,FS:IRQ0INTNO
  687.                CALL           PMSETPMIV      ;Will ignore any error here.
  688.                                              ;We couldn't do anything else.
  689.  
  690. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  691. ;   Here is where we go back to real mode for good.  But keep on reading.       
  692. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  693.  
  694.                RET                           ;Goodbye protected, ole pal
  695.  
  696. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  697. ;   Now, let's look at our protected-mode handler.  Comments are below.
  698. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  699.  
  700. TIMERINT       PROC FAR
  701.                STI
  702.                PUSH           EAX
  703.                PUSH           DS             
  704.                MOV            DS,CS:CSDSEGSEL  ;Load DSEG selector
  705.                MOV            DS,FLATDSEL      ;Load flat selector for PMIO
  706.                MOV            AL,"*"
  707.                CALL           PCH              ;Print AL as ASCII
  708.                CLI
  709.                MOV            AL,20H           ;Send EOI to 8259 master
  710.                OUT            20H,AL
  711.                POP            DS
  712.                POP            EAX
  713.                IRETD
  714. TIMERINT       ENDP
  715.  
  716. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  717. ;   As you probably know, we are not supposed to assume anything about 
  718. ;anything in an interrupt handler, including segment register settings.  Now
  719. ;XLIBE has recorded our selector values in DSEG (see manual).  However, we
  720. ;have a little problem here:  We need the DSEG selector to get them.  The
  721. ;way we circumvent this dilemma is by putting a copy of the DSEG selector in
  722. ;your code segment where you can always read it.  XLIBE has already done
  723. ;this for you.  It placed the selector in CSDSEGSEL.
  724. ;   After we have loaded DS with DSEGSEL, we then load it with the flat 
  725. ;selector.  This is recorded in FLATDSEL.
  726. ;   You might be wondering why we didn't use a DOS function to do our 
  727. ;printing.  It's because you can bring a system down real hard and real fast
  728. ;by calling DOS in an interrupt handler.  The problem occurs when DOS is
  729. ;itself interrupted.  DOS is not generally reentrant.  The print routines in
  730. ;PMIO are very robust.  They are also fast.
  731. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  732.  
  733. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  734. ;  OK.  You are hopefully an XLIB programmer now.  Remember that XLIB is not
  735. ;free.  You must register it once you have developed any program with it.
  736. ;The fee is only $50 ($70 with technical support).  If you think that is bad,
  737. ;then you should look at the retail DOS extenders.  You are talking about
  738. ;a lot more money and a lot more work.  We appreciate your business
  739. ;
  740. ;                                                 TechniLib
  741. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  742.  
  743. PMMAIN         ENDP
  744.  
  745.                INCLUDE        PMIO.INC       ;Protected-mode IO routines
  746.  
  747. TSEG           ENDS
  748.                END
  749.  
  750. ;*****************************************************************************
  751. ;                              Special Notes
  752. ;*****************************************************************************
  753.  
  754. ;                      ++++++++++++++++++++++++++++
  755. ;                      +     Writing Libraries    +
  756. ;                      ++++++++++++++++++++++++++++
  757. ;
  758. ;
  759. ;   You can give high-level language programs tremendous power by linking 
  760. ;them with protected-mode libraries developed with XLIBE.  See the EASYX.ASM 
  761. ;file for an example.
  762. ;
  763. ;
  764. ;                          ++++++++++++++++++++                                 
  765. ;                          +     Page Mode    +
  766. ;                          ++++++++++++++++++++
  767. ;
  768. ;
  769. ;   We discuss something here that's a little technical, but extremely
  770. ;enlightening.  It's called "page mode," available only in protected mode or
  771. ;in virtual 8086 mode, which is of course a subset of protected mode.  In
  772. ;page mode, memory addresses specified in instruction code undergo a little
  773. ;mathematical translation before they are actually applied to the physical 
  774. ;memory.  So what you ask for isn't always what you get.  For example, if
  775. ;you write something to address 10000H, it might actually go to 20000H.  This
  776. ;isn't bad as long as when you read from 10000H you also get 20000H, and
  777. ;indeed you will.  Incidentally, the address you specify is called a 
  778. ;"logical" address.  The address you actually get is called the "physical"
  779. ;address.
  780. ;   Now, a lot of mysteries may have just been explained to you.  For 
  781. ;example, you know that most of your programs must reside in the first meg.
  782. ;You also know that many of your programs consume most of the available 
  783. ;memory in the first meg.  How then do DESQview, Windows, OS/2, etc. run all
  784. ;of these programs at the same time???  Well, you give each program a 
  785. ;different translation formula.  Stick the first program in the first meg and
  786. ;give it one-to-one translation.  No trickery here.  Stick the second program
  787. ;in the second meg and then add 1 meg (100000H) to every address it tries to 
  788. ;read and write.  Remember, this program thinks it's in the first meg, so
  789. ;that's where it's going to be reading and writing.  But, because of the 
  790. ;translation, it's going to be getting the second meg.  This program has been 
  791. ;fooled.  It has been hornswoggled by page mode.
  792. ;   Perhaps you have wondered how your memory manager put your device drivers
  793. ;and TSRs in upper memory where ROM is supposed to be.  The answer is page 
  794. ;mode again.  The device drivers and TSRs are actually in extended memory.
  795. ;The logical addresses which would otherwise belong to the ROM area have been
  796. ;translated to these extended memory addresses.
  797. ;   Before explaining what all this has to do with you, let's explain the
  798. ;translation method.  The logical address you specify is of course 32 bits 
  799. ;wide.  We are going to divide these three ways:  the 10 upper bits, the 
  800. ;next ten bits, and the lowest 12 bits.  The translation runs thus:  The 10 
  801. ;highest bits are used as an index to a table which has 1024 entries.  These 
  802. ;entries are 4 bytes wide so the table consumes 4K.  These entries are 
  803. ;physical addresses to other tables which are also 4K in size.  We use your 
  804. ;upper 10 bits to pick the appropriate table.  Your next 10 bits will be used 
  805. ;as an index to the second-level table.  The entries in this table supply the 
  806. ;upper 20 bits to the physical address you are actually going to access.  The 
  807. ;lowest 12 bits of the physical address are supplied by the lowest 12 bits in 
  808. ;your logical address.  A mess isn't it.  Don't worry, you are not responsible
  809. ;for handling this mess, but sometimes XLIBE is.
  810. ;   Now, the second-level table supplies all but the 12 lowest bits of the
  811. ;physical memory address; therefore, the addresses in this table are spaced 
  812. ;in memory at least 4096 bytes apart (2 ^ 12 = 4096).  The memory is 
  813. ;effectively divided into 4K units along 4K boundaries.  These 4K units are 
  814. ;called "pages," hence the term "page mode."
  815. ;   The first-level table is called a "page directory."  The tables at the 
  816. ;second level are called "page tables."  You typically give each program its 
  817. ;own page directory and page tables.  This is how we use a different 
  818. ;translation method for each program.
  819. ;   One of the most effective ways to protect a physical page from a
  820. ;particular program is to simply avoid placing the address of the page in the 
  821. ;program's page tables.  If the address of a physical page is not anywhere
  822. ;in the page tables, then there is no way that the program can access it,
  823. ;provided of course that we also prevent the program from playing with the 
  824. ;page tables themselves.  Hence, we could completely shield one program from
  825. ;another.  This largely explains how OS/2 and Windows NT achieve such high
  826. ;degrees of protection.
  827. ;   Now the page tables are themselves pages.  That is, they are 4K in size
  828. ;and are situated on 4K physical address boundaries.  This means that their
  829. ;addresses are zero in the lowest 12 bits.  The pages they catalog are also
  830. ;zero in the lowest 12 address bits.  This means that for each entry in the 
  831. ;page directory and for each entry in the page tables we have 12 bits to play 
  832. ;with (the lowest 12) because we never need them for address specification.
  833. ;   An operating system can use certain of these bits to implement other
  834. ;protection mechanisms of the processor.  For example, the operating system 
  835. ;can use one of these bits to designate the page as read-only.  Try to write 
  836. ;to it and you are going to get a page fault (exception #14).  A page can 
  837. ;also be marked as privileged.  This means that the operating system can
  838. ;access it but most other programs cannot.  
  839. ;   Another important bit in the page tables is the "present" bit.  This bit
  840. ;is set if there is actually a physical page available for the implied 
  841. ;logical address.  What happens when you try to access a logical address
  842. ;whose page table entry is marked not present?  Well, you are going to get
  843. ;another page fault.  Under XLIBE this almost certainly means that your
  844. ;program is going to get terminated.  Indeed, XLIBE will usually be 
  845. ;responsible for terminating you (gently if at all possible).  Which explains
  846. ;one of the reasons why you need to understand page mode.  Page faults are
  847. ;going to become a major part of your protected-mode life.  If your program
  848. ;has a wild read or write, or a bad JMP or CALL, or a RET or IRET with
  849. ;a mismanaged stack, then page faults are likely.  
  850. ;   Some operating systems and memory managers have "virtual memory."  This
  851. ;is where you are using disk to emulate memory.  The operating system may
  852. ;give you a logical address block which really doesn't have any physical
  853. ;memory to back it up.  The page table entries for this logical address block
  854. ;are all marked not present.  When you try to access one of these logical 
  855. ;addresses, the resultant page fault is trapped by the operating system, 
  856. ;which then pulls the requested page off the disk and places it in a special 
  857. ;memory area designed for such purposes.  Your page table entry is then 
  858. ;pointed to this location and is marked present.  Finally, control is 
  859. ;returned to you.  You may never know what happened.
  860. ;   You can actually use virtual memory under XLIB.  Just get a DPMI host
  861. ;with virtual memory capabilities.
  862.  
  863.  
  864.                         +++++++++++++++++++++++
  865.                         +    FPU Exceptions   +
  866.                         +++++++++++++++++++++++
  867.  
  868.  
  869. ;   Floating point exceptions are handled a bit differently than CPU 
  870. ;exceptions by XLIBE.  Suppose you had a major goofup in your code like this:
  871. ;
  872. ;              FLD1                          ;Load 1.0
  873. ;              FLDZ                          ;Load 0.0
  874. ;              FDIV                          ;Compute 1.0/0.0 (very sinful)
  875. ;              FSTP           ST             ;Pop the "quotient"
  876. ;
  877. ;The FDIV will cause a zero divide exception in the FPU.  This exception will
  878. ;not be signalled to the CPU until the next floating point instruction.  So
  879. ;the FSTP ST instruction is where things are going to happen.
  880. ;   Under default behavior, XLIBE is going to trap this exception and display
  881. ;a report describing the cause and location of the exception.  XLIBE will
  882. ;terminate your program after presenting the report.  If you don't like the
  883. ;default behavior of XLIBE, then XLIBE can be configured such that it will
  884. ;turn control over to you when such exceptions occur.  Study the OFLAGS
  885. ;variable in the XLIB documentation for more about this.
  886.